Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Root certs are not used on Windows #67

Open
wants to merge 15 commits into
base: main
Choose a base branch
from

Conversation

Kurlee
Copy link

@Kurlee Kurlee commented Jul 27, 2020

The implementation of the verify command fails to read from the system root store on Windows. This was likely done due to issues with the x509 library which fails to parse the root store as detailed in Issue #16736 of the golang crypto library. Windows instead was defaulting to the gocertifi library, which prevents users from adding or removing trusted roots, and verifying signatures against those roots.

In the golang crypto issue referenced before, there is a workaround which enables us to parse the root store and verify signatures against these roots. I have adopted this fix to this project.

All tests passing locally.

Thanks to @ndouthit for help in troubleshooting this issue.

…stead was defaulting to the gocertifi library. This bug prevents users from adding trusted roots and verifying signatures using those roots
@Kurlee
Copy link
Author

Kurlee commented Jul 27, 2020

I see these tests failing on OSX, I will address this by first attempting to read the store using x509.SystemCertPool() call to basically test if I am on Windows or OSX and proceed from there

Adrian Hassan Abdala added 3 commits July 27, 2020 08:56
@Kurlee
Copy link
Author

Kurlee commented Jul 27, 2020

Apologies for the bad initial request. Testing was passing locally, but failed in travis due to OSX throwing errors with the windows specific syscall methods. Tests are now passing with the go 1.12 and 1.x configurations and failing on master. This is consistent with the state of the project before this fix.

@ptoomey3
Copy link
Member

Thanks for opening the PR. We have one other PR that is also failing CI for similar reasons (I think). Let us take a look at that and circle back.

@Kurlee
Copy link
Author

Kurlee commented Jul 27, 2020

It isn't just the other PR that is failing CI, the whole project failed for the go: master configuration since the latest commit 7e96b8b.

@Kurlee
Copy link
Author

Kurlee commented Jul 28, 2020

@ptoomey3, the failing Travis tests are not due to any issue with the changes contained in this PR. Unit tests are passing on the 1.12 and 1.14 golang configurations in Travis. I opened an issue to address the failing Travis tests here, and I'll happily help troubleshoot this issue.

Respectfully request that you ignore the current state of Travis testing to address the issue with Windows Cert store. The results of these tests match the latest commit to this project.

@ptoomey3
Copy link
Member

Thanks for opening the issue. Someone on our team plans to take a look this later this week.

@Kurlee
Copy link
Author

Kurlee commented Aug 10, 2020

As soon as #69 gets pulled in, I'll update this branch so CI will be passing. Can I get an estimate since getting the Windows root store fix is important to my project? @ptoomey3

@ptoomey3
Copy link
Member

We will chat about it on our team call today.

@lgarron lgarron changed the base branch from master to main August 12, 2020 00:57
@Kurlee
Copy link
Author

Kurlee commented Aug 19, 2020

Thank you @lgarron! All unit tests passing

@Kurlee
Copy link
Author

Kurlee commented Dec 10, 2020

Can I get a quick update on this? It's been a few months

Copy link
Member

@vcsjones vcsjones left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many thanks for the patience on a review! My initial thought is, in principle, I like the idea of this change so that roots in the System store are considered as valid anchors.

However, as discussed in the golang/go#16736 (comment), enumerating the Windows Machine/Root trust store is problematic in that it is dynamically populated. So, even though a certificate is theoretically in this trust store, it won't be in the enumeration unless the authroot STL has been pulled down. This is why Go's pull request to implement this was reverted.

With this change, it seems possible or likely that root certificates that were once being returned will now be missing.

Perhaps this can be implemented this as a union of gocertifi's NSS roots and the Windows store and de-duplicate the results. That way roots that were returned previously will continue to be returned, and anything new in the Windows trust store will be added.

if err != nil {
return errors.Wrap(err, "Failed to get root store name")
}
storeHandle, err := syscall.CertOpenSystemStore(0, storeName)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see a call to CertCloseStore anywhere, so I think this is leaking HCERTSTORE handles.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a defered call to CertCloseStore to resolve this.

lgarron and others added 10 commits December 21, 2020 11:00
The chain in question is defined in RFC5652 as a CertificateSet, which is a `SET OF` certs:

- https://tools.ietf.org/html/rfc5652#section-5.1
- https://tools.ietf.org/html/rfc5652#section-10.2.3

Go 1.15 introduced a change that sorts such sets: https://go.googlesource.com/go/+/f0cea848679b8f8cdc5f76e1b1e36ebb924a68f8

Our tests were implicitly relying on the sets to stay sorted, but the right thing to do at this point is update our tests.
…e Certificate Store when completed enumarating trusted roots on Windows
…oots to this pool. Duplicate certs are automatically dropped
@Kurlee
Copy link
Author

Kurlee commented Dec 21, 2020

Thanks for the review @vcsjones. I have addressed your concern about unreliable enumeration of the windows root store in the following way.
I used gocertifi to initialize the CertPool and then add the system certificates to this pool. The 'x509.CertPool.AddCert' function contains logic to prevent a duplicate cert from being added to the pool, so de-duplication is not required.

I hope this addresses your concerns sufficiently. There is still a chance that trusted certificates that are not in the Mozilla trusted roots bundle will not be enumerated and verification will fail, but there is now a baseline of trusted certificates which will always populate.

@Kurlee
Copy link
Author

Kurlee commented Mar 13, 2021

Been a few months. Can I get a checkup on this?

Copy link
Member

@vcsjones vcsjones left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks again for your patience. I had one last suggestion to make sure we're as close-as-possible with compatibility with the previous implementation.

return errors.Wrap(err, "Failed to parse root store")
}

for _, ident := range idents {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should also continue to fallback to gocertifi.CACerts() if we cannot open the SystemCertPool on macOS / Linux.

While the fallback path was primarily there for Windows support, macOS could still have a non-nil err if opening the root store failed.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, I’ll go ahead and get to work on implementing this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants